﻿using EncryptUtils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace ACE
{
    public partial class FormMain : Form
    {
        List<Controller> Controllers = new List<Controller>();
        private TreeNode RightClickedNode;
        private TreeNode SelectedNode;

        public FormMain()
        {
            InitializeComponent();
        }

        private void LoadControllers()
        {
            int i = 0;
            var controllerUrl = ConfigUtils.ReadSetting(string.Format("{0}_{1}", "ControllerUrl", i.ToString()), "");
            while (!string.IsNullOrEmpty(controllerUrl))
            {
                var account = ConfigUtils.ReadSetting(string.Format("{0}_{1}", "Account", i.ToString()), "customer1");
                var userName = ConfigUtils.ReadSetting(string.Format("{0}_{1}", "UserName", i.ToString()), "");
                var portalLogin = ConfigUtils.ReadSetting(string.Format("{0}_{1}", "PortalLogin", i.ToString()), "");
                string encryptedPwd = ConfigUtils.ReadSetting(string.Format("{0}_{1}", "Password", i.ToString()), "");
                string password = "";
                if (!string.IsNullOrEmpty(encryptedPwd) && !string.IsNullOrEmpty(userName))
                {
                    password = DE2.DecryptString(encryptedPwd, userName);
                }

                //Todo: better way to search controller list
                var found = false;
                foreach (Controller c in Controllers)
                {
                    if(string.Equals(c.ControllerUrl, controllerUrl, StringComparison.CurrentCultureIgnoreCase))
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    Controllers.Add(new Controller(i, controllerUrl, account, userName, password, portalLogin));
                    var treeNode = treeViewApps.Nodes.Add(controllerUrl);
                    treeNode = treeNode.Nodes.Add("Applications");
                    treeNode.Nodes.Add("Loading...");
                }
                i++;
                controllerUrl = ConfigUtils.ReadSetting(string.Format("{0}_{1}", "ControllerUrl", i.ToString()), "");
            }
        }

        private bool AddController()
        {
            var controller = new Controller();
            var formConnect = new FormConnect(controller);
            formConnect.ShowDialog();
            if (controller.Authenticated)
            {
                return true;
            }
            return false;
        }

        private bool LoadConnectForm(Controller controller)
        {
            var formConnect = new FormConnect(controller);
            formConnect.ShowDialog();
            if (controller.Authenticated)
            {
                return true;
            }
            return false;
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            LoadControllers();

            comboBoxDuration.Items.Add("5");
            comboBoxDuration.Items.Add("15");
            comboBoxDuration.Items.Add("30");
            comboBoxDuration.Items.Add("60");
            comboBoxDuration.Items.Add("120");
            comboBoxDuration.Items.Add("180");
            comboBoxDuration.Items.Add("240");
            comboBoxDuration.Items.Add("360");
            comboBoxDuration.Items.Add("720");
            comboBoxDuration.Items.Add("1440");
            comboBoxDuration.Items.Add("4320");
            comboBoxDuration.Items.Add("10080");
            comboBoxDuration.Items.Add("20160");
            comboBoxDuration.Items.Add("40320");
            comboBoxDuration.SelectedIndex = 9;

            comboBoxMetricCategory.Items.Add("Overall Application Performance");
            comboBoxMetricCategory.Items.Add("Business Transaction Performance");
            comboBoxMetricCategory.Items.Add("Application Infrastructure Performance");
            comboBoxMetricCategory.SelectedIndex = 0;

            comboBoxMetricName.Items.Add("Calls per Minute");
            comboBoxMetricName.Items.Add("Average Response Time (ms)");
            comboBoxMetricName.Items.Add("Errors per Minute");
            comboBoxMetricName.Items.Add("Exceptions per Minute");
            comboBoxMetricName.Items.Add("Number of Slow Calls");
            comboBoxMetricName.Items.Add("Number of Very Slow Calls");
            comboBoxMetricName.Items.Add("Stall Count");
            comboBoxMetricName.SelectedIndex = 0;

            checkBoxClearSeries.Checked = true;
            pictureBox1.Visible = false;

            //Trigger form resize event
            var formWindowState = ConfigUtils.ReadSetting("FormState", "");
            var formLeft = ConfigUtils.ReadSetting("FormLeft", "");
            var formTop = ConfigUtils.ReadSetting("FormTop", "");
            var formWidth = ConfigUtils.ReadSetting("FormWidth", "");
            var formHeight = ConfigUtils.ReadSetting("FormHeight", "");

            Form f = (FormMain)sender;
            f.Width = f.Width + 1;
            f.Width = f.Width - 1;
            splitContainerChart.SplitterDistance = splitContainerChart.SplitterDistance + 1;
            if (formLeft == "" || formTop == "" || formWidth == "" || formHeight == "")
            {
                f.StartPosition = FormStartPosition.CenterScreen;
            }
            else
            {
                if (formWindowState == "1")
                {
                    f.WindowState = FormWindowState.Maximized;
                }
                else
                {
                    f.Left = Convert.ToInt32(formLeft);
                    f.Top = Convert.ToInt32(formTop);
                    f.Width = Convert.ToInt32(formWidth);
                    f.Height = Convert.ToInt32(formHeight);
                }
            }
            //ConfigUtils.ReadSetting()
        }

        private void buttonGetMetrics_Click(object sender, EventArgs e)
        {
            Hourglass(true);
            var controller = GetController(treeViewApps.SelectedNode);
            Chart chart1 = chartMetricData;

            var metricCategory = comboBoxMetricCategory.Items[comboBoxMetricCategory.SelectedIndex].ToString();
            var metricName = comboBoxMetricName.Items[comboBoxMetricName.SelectedIndex].ToString();
            var durationInMinutes = comboBoxDuration.Items[comboBoxDuration.SelectedIndex].ToString();

            var applicationName = string.Empty;
            var tierName = string.Empty;
            var btName = string.Empty;
            
            List<ADApplication> applications;

            if (checkBoxClearSeries.Checked)
            {
                ClearSeries(chart1);
            }

            switch (treeViewApps.SelectedNode.Level)
            {
                case 0:
                    applications = controller.GetApplications("");
                    foreach(ADApplication a in applications)
                    {
                        PlotMetric(chart1, controller, a.Name, tierName, btName, metricCategory, metricName, durationInMinutes, checkBoxClearSeries.Checked);
                    }
                    break;
                case 1:
                    if (treeViewApps.SelectedNode.Text.ToLower() == "applications")
                    {
                        applications = controller.GetApplications("");
                        foreach(ADApplication a in applications)
                        {
                            PlotMetric(chart1, controller, a.Name, tierName, btName, metricCategory, metricName, durationInMinutes, checkBoxClearSeries.Checked);
                        }
                    }
                    break;
                case 2:
                    applicationName = treeViewApps.SelectedNode.Text;
                    PlotMetric(chart1, controller, applicationName, tierName, btName, metricCategory, metricName, durationInMinutes, checkBoxClearSeries.Checked);
                    break;
                case 3:
                    break;
                case 4:
                    applicationName = treeViewApps.SelectedNode.Parent.Parent.Text;
                    btName = treeViewApps.SelectedNode.Text;
                    PlotMetric(chart1, controller, applicationName, tierName, btName, metricCategory, metricName, durationInMinutes, checkBoxClearSeries.Checked);
                    break;
                case 5:
                    break;
                case 6:
                    applicationName = treeViewApps.SelectedNode.Parent.Parent.Parent.Parent.Text;
                    tierName = treeViewApps.SelectedNode.Parent.Parent.Text;
                    btName = treeViewApps.SelectedNode.Text;
                    PlotMetric(chart1, controller, applicationName, tierName, btName, metricCategory, metricName, durationInMinutes, checkBoxClearSeries.Checked);
                    break;
            }

            Hourglass(false);
        }

        private void PlotMetric(Chart chart1, Controller controller, string applicationName, string tierName, string btName, string metricCategory, string metricName, string durationInMinutes, bool clearSeries)
        {
            var metricData = controller.GetMetrics(applicationName, tierName, btName, metricCategory, metricName, durationInMinutes);

            //Remove any existing titles
            while (chart1.Titles.Count > 0)
            {
                Title t = chart1.Titles.FindByName(chart1.Titles[0].Name);
                if (t != null)
                {
                    chart1.Titles.Remove(t);
                }
            }

            //Add a chart title
            chart1.Titles.Add("Title1");
            chart1.Titles["Title1"].Text = "Overall Application Performance";

            //Add series data
            foreach (Metric m in metricData)
            {
                var fullMetricPath = string.Format("{0}-{1}", applicationName, m.MetricPath);
                //This is unneccessary, but just to be sure checking for existing
                Series s = chart1.Series.FindByName(fullMetricPath);
                if (s != null)
                {
                    chart1.Series.Remove(s);
                }

                chart1.Series.Add(fullMetricPath);
                chart1.Series[fullMetricPath].ChartType = SeriesChartType.Line;

                int i = 0;
                foreach (MetricValue mv in m.MetricValues)
                {
                    chart1.Series[fullMetricPath].Points.AddXY(i++, mv.Value);
                }
            }
        }

        private static void ClearSeries(Chart chart1)
        {
            //Remove any existing series
            while (chart1.Series.Count > 0)
            {
                Series s = chart1.Series.FindByName(chart1.Series[0].Name);
                if (s != null)
                {
                    chart1.Series.Remove(s);
                }
            }
        }

        private void comboBoxDuration_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void treeViewApps_AfterSelect(object sender, TreeViewEventArgs e)
        {
            Hourglass(true);
            SelectedNode = e.Node;
            if (e.Node.Level > 0)
            {
                if (e.Node.Text.ToLower() == "applications" || e.Node.Parent.Text.ToLower() == "applications")
                {
                    GetApplicationInfo(e.Node);
                }

                if (e.Node.Text.ToLower() == "servers" || e.Node.Parent.Text.ToLower() == "servers")
                {
                    GetServerInfo(e.Node);
                }

                if (e.Node.Text.ToLower() == "tiers" || e.Node.Parent.Text.ToLower() == "tiers")
                {
                    GetTierInfo(e.Node);
                }

                if (e.Node.Text.ToLower() == "bts" || e.Node.Parent.Text.ToLower() == "bts")
                {
                    GetBTInfo(e.Node);
                }
            }

            Hourglass(false);
        }

        private void treeViewApps_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            Hourglass(true);

            var node = e.Node;
            Controller controller;
            switch (node.Text)
            {
                case "Applications":
                    controller = GetController(e.Node);

                    if (!Authenticate(controller))
                    {
                        e.Cancel = true;
                        return;
                    }

                    LoadApplications(node, controller);
                    break;
                case "Tiers":
                    controller = GetController(e.Node);
                    LoadTiers(node, controller);
                    break;
                case "Servers":
                    controller = GetController(e.Node);
                    LoadServers(node, controller);
                    break;
                case "BTs":
                    controller = GetController(e.Node);
                    LoadBTs(node, controller);
                    break;
                default:
                    break;
            }
            Hourglass(false);
        }

        private void Hourglass(bool Show)
        {
            if (Show == true)
            {
                System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.WaitCursor;
            }
            else
            {
                System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Default;
            }
            return;
        } 

        private void LoadBTs(TreeNode node, Controller controller)
        {
            var application = GetApplicationName(node);

            //todo: better way of getting tier
            var tierName = node.Level == 3 ? "": node.Parent.Text;

            var bts = controller.GetBTs(application, tierName, "");
            node.Nodes.Clear();

            foreach (BT bt in bts)
            {
                TreeNode tnTiers = node.Nodes.Add(bt.Name);
            }
        }

        private void LoadServers(TreeNode node, Controller controller)
        {
            var application = GetApplicationName(node);

            //todo: better way of getting tier
            var tierName = node.Level == 3 ? "" : node.Parent.Text;

            var nodes = controller.GetNodes(application, tierName, "", true);
            node.Nodes.Clear();

            foreach (Node n in nodes)
            {
                TreeNode tnTiers = node.Nodes.Add(n.MachineName);
            }
        }

        private string GetApplicationName(TreeNode node)
        {
            TreeNode tn = node;
            while (tn.Level > 2)
            {
                tn = tn.Parent;
            }
            return tn.Text;
        }
        private string GetTierName(TreeNode node)
        {
            TreeNode tn = node;
            while (tn.Level > 2 && tn.Parent.Text.ToLower() != "tiers")
            {
                tn = tn.Parent;
            }
            if (tn.Parent.Text.ToLower() == "tiers")
            {
                return tn.Text;
            }
            return "";
        }

        private void LoadTiers(TreeNode node, Controller controller)
        {
            var application = node.Parent.Text;
            var tiers = controller.GetTiers(application, "");
            node.Nodes.Clear();

            foreach(Tier tier in tiers)
            {
                TreeNode[] tn = new TreeNode[2];
                tn[0] = new TreeNode("Servers");
                tn[0].Nodes.Add("Loading...");
                tn[1] = new TreeNode("BTs");
                tn[1].Nodes.Add("Loading...");

                TreeNode tnTiers = node.Nodes.Add(tier.Name);
                tnTiers.Nodes.AddRange(tn);
            }
        }

        private static void LoadApplications(TreeNode node, Controller controller)
        {
            if (string.Equals(node.Nodes[0].Text, "Loading...", StringComparison.InvariantCulture))
            {
                var applications = controller.GetApplications("");

                node.Nodes.Clear();

                foreach (ADApplication a in applications)
                {
                    TreeNode[] tn = new TreeNode[3];
                    tn[0] = new TreeNode("Tiers");
                    tn[0].Nodes.Add("Loading...");
                    tn[1] = new TreeNode("Servers");
                    tn[1].Nodes.Add("Loading...");
                    tn[2] = new TreeNode("BTs");
                    tn[2].Nodes.Add("Loading...");

                    TreeNode apps = node.Nodes.Add(a.Name);
                    apps.Nodes.AddRange(tn);
                }
            }
        }

        private bool Authenticate(Controller controller)
        {
            if (!controller.Authenticated)
            {
                try
                {
                    controller.Authenticate();
                }
                catch (Exception)
                {
                    //Error Authenticating
                }
                if (!controller.Authenticated)
                {
                    if (!LoadConnectForm(controller))
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        private Controller GetController(TreeNode tn)
        {
            while (tn.Level > 0)
            {
                tn = tn.Parent;
            }
            var controllerUrl = tn.Text;

            foreach (Controller c in Controllers)
            {
                if(string.Equals(c.ControllerUrl, controllerUrl, StringComparison.InvariantCulture))
                {
                    return c;
                }
            }
            return null;
        }

        private void addControllerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddController();
            LoadControllers();
        }

        private void connectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var controller = GetController(SelectedNode);
            LoadConnectForm(controller);
            //Authenticate();
            //if (!Controllers[0].Authenticated)
            //{
            //    this.Close();
            //}
        }


        private void contextMenuStripTreeView_MouseClick(object sender, MouseEventArgs e)
        {
            var contextMenu = (ContextMenuStrip)sender;
            //contextMenu.Items[contextMenu.item]

            //Point pt = contextMenu.p
            var treeView = (TreeView)contextMenu.SourceControl;
            //Point p = new Point(treeView.Location.X, treeView.Location.Y);
            Point p = new Point(e.X, e.Y);
            //TreeNode tn = treeView.GetNodeAt(p);
            //var nt = tn.Text;

            //if (treeView.SelectedNode != null)
            //{
            //    var nodeText = treeView.SelectedNode.Text;
            //}

            var text = RightClickedNode.Text;

        }

        private void treeViewApps_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                Point pt = new Point(e.X, e.Y);
                var treeView = (TreeView)sender;
                TreeNode tn = treeView.GetNodeAt(pt);
                RightClickedNode = tn;
                contextMenuStripTreeView.Show(pt);
            }
        }

        private void contextMenuStripTreeView_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            var currentNodeText = RightClickedNode.Text;
            var parentNodeText = RightClickedNode.Parent== null ? null: RightClickedNode.Parent.Text.ToLower();
            switch (e.ClickedItem.Text.ToLower())
            {
                case "more information":
                    switch (parentNodeText)
                    {
                        case null:
                            break;
                        case "applications":
                            break;
                        case "bts":
                            break;
                        case "tiers":
                            break;
                        case "servers":
                            GetServerInfo(RightClickedNode);
                            break;
                    }
                    break;
                case "add to graph":
                    break;
                default:
                    break;
            }
        }

        private void GetApplicationInfo(TreeNode node)
        {
            var controller = GetController(node);
            var application = node.Parent.Text.ToLower() == "applications" ? node.Text : "";

            var applications = controller.GetApplications(application);
            
            dataGridViewServers.DataSource = applications;
        }

        private void GetServerInfo(TreeNode node)
        {
            var controller = GetController(node);
            var application = GetApplicationName(node);
            var tierName = GetTierName(node);
            var serverName = node.Parent.Text.ToLower() == "servers" ? node.Text : "";

            var nodes = controller.GetNodes(application, tierName, serverName, false);

            dataGridViewServers.DataSource = nodes;
        }
        private void GetTierInfo(TreeNode node)
        {
            var controller = GetController(node);
            var application = GetApplicationName(node);
            //var tierName = GetTierName(node);
            var tierName = node.Parent.Text.ToLower() == "tiers" ? node.Text : "";

            var tiers = controller.GetTiers(application, tierName);

            dataGridViewServers.DataSource = tiers;
        }

        private void GetBTInfo(TreeNode node)
        {
            var controller = GetController(node);
            var application = GetApplicationName(node);
            var tierName = GetTierName(node);
            var btName = node.Parent.Text.ToLower() == "bts" ? node.Text : "";

            var BTs = controller.GetBTs(application, tierName, btName);

            dataGridViewServers.DataSource = BTs;
        }

        private void treeViewApps_Click(object sender, EventArgs e)
        {
            var treeView = (TreeView)sender;
        }

        private void FormMain_Resize(object sender, EventArgs e)
        {
            Form f = (FormMain)sender;
            splitContainer1.Width = (f.Width - splitContainer1.Left) - 30;
            splitContainer1.Height = (f.Height - splitContainer1.Top) - 50;

            splitContainerChart.Width = splitContainer1.Panel2.Width - 50;
            splitContainerChart.Height = splitContainer1.Panel2.Height - 50;
        }

        private void splitContainer1_Panel2_Resize(object sender, EventArgs e)
        {
            treeViewApps.Width = splitContainer1.Panel1.Width - 5;
            tabControl1.Width = splitContainer1.Panel2.Width - 5;
            chartMetricData.Width = splitContainerChart.Panel1.Width - 5;
            dataGridViewServers.Width = tabControl1.Width - 5;

            treeViewApps.Height = splitContainer1.Panel1.Height - 5;
            tabControl1.Height = splitContainer1.Panel2.Height - 5;
            chartMetricData.Height = splitContainerChart.Panel1.Height - 5;
            dataGridViewServers.Height = tabControl1.Height - 5;
        }

        private void splitContainerChart_SplitterMoved(object sender, SplitterEventArgs e)
        {
            chartMetricData.Width = splitContainerChart.Panel1.Width - 5;
            chartMetricData.Height = splitContainerChart.Panel1.Height - 5;
        }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            Form f = (FormMain)sender;

            if (f.WindowState == FormWindowState.Maximized)
            {
                ConfigUtils.AddUpdateAppSetting("FormState", "1");
            }
            else
            {
                ConfigUtils.AddUpdateAppSetting("FormState", "0");
                ConfigUtils.AddUpdateAppSetting("FormLeft", f.Left.ToString());
                ConfigUtils.AddUpdateAppSetting("FormTop", f.Top.ToString());
                ConfigUtils.AddUpdateAppSetting("FormWidth", f.Width.ToString());
                ConfigUtils.AddUpdateAppSetting("FormHeight", f.Height.ToString());
            }
        }

        private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {

        }
    }
}
